#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <WinSock2.h>

#include "CommRecv.h"
#include "../include/ReadConf.h"

#pragma comment(lib, "Ws2_32.lib")


int main(void)
{
	SOCKET ssd, csd;
	SOCKADDR_IN saddr, caddr;
	int clen;
	struct msg_cmt_st *cmt;
	int cmt_size;
	unsigned int tmpfile_no;
	int ret;

	read_conf();
	
	ret = begin_socket();
	if (ret == -1) {
		return -1;
	}

	ssd = socket(AF_INET, SOCK_STREAM, 0);
	if (ssd == INVALID_SOCKET) {
		perror("socket()");
		exit(1);
	}

	memset(&saddr, 0, sizeof(saddr));
	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(get_conn_port());
	//saddr.sin_addr.S_un.S_addr = inet_addr(get_server_ipaddr());
	saddr.sin_addr.S_un.S_addr = inet_addr("0.0.0.0");
	if (saddr.sin_addr.S_un.S_addr == INADDR_NONE) {
		exit(1);
	}
	ret = bind(ssd, (SOCKADDR *)&saddr, sizeof(SOCKADDR));
	if (ret == SOCKET_ERROR) {
		perror("bind()");
		exit(1);
	}

	ret = listen(ssd, 255);
	if (ret == SOCKET_ERROR) {
		perror("listen()");
		exit(1);
	}

	cmt = NULL;
	cmt_size = 0;
	tmpfile_no = 0;
	while (1) {
		clen = sizeof(caddr);
		csd = accept(ssd, (SOCKADDR *)&caddr, &clen);
		if (csd == INVALID_SOCKET) {
			perror("accept()");
			continue;
		}

		ret = read_comm(csd, &cmt, &cmt_size);
		if (ret == -1) {
			closesocket(csd);
			continue;
		}
		ret = write_comm(tmpfile_no, &cmt);
		if (ret != -1) {
			tmpfile_no++;
		}
		closesocket(csd);
	}

	closesocket(ssd);
	exit(0);
}

static int begin_socket(void)
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested=MAKEWORD(1,1);
 
    err=WSAStartup(wVersionRequested,&wsaData);
    if (err!=0) {
		return -1;
	}
 
    if (LOBYTE(wsaData.wVersion)!=1||HIBYTE(wsaData.wVersion)!=1) {
        WSACleanup();
        return -1;
    }

	return 0;
}

static int read_comm(int sock, struct msg_cmt_st **cmt, int *cmt_size)
{
	void *retc;
	int ret, pos, len;

	if (*cmt_size < sizeof(**cmt)) {
		*cmt_size = sizeof(**cmt);
	}
	retc = realloc(*cmt, *cmt_size);
	if (retc == NULL) {
		if (*cmt != NULL) {
			free(*cmt);
		}
		return -1;
	}
	*cmt = retc;

	len = sizeof(**cmt);
	pos = 0;
	while (len > 0) {
		ret = recv(sock, (char *)*cmt + pos, len, 0);
		if (ret == SOCKET_ERROR) {
			perror("recv()");
			free(*cmt);
			return -1;
		}
		pos += ret;
		len -= ret;
	}

	if (*cmt_size < (int)(sizeof(**cmt) + ntohl((*cmt)->offset))) {
		*cmt_size = sizeof(**cmt) + ntohl((*cmt)->offset);
	}
	retc = realloc(*cmt, *cmt_size);
	if (retc == NULL) {
		if (*cmt != NULL) {
			free(*cmt);
		}
		return -1;
	}
	*cmt = retc;

	len = ntohl((*cmt)->offset);
	pos = 0;
	while (len > 0) {
		ret = recv(sock, &((*cmt)->data[1]) + pos, len, 0);
		if (ret == SOCKET_ERROR) {
			perror("recv()");
			free(*cmt);
			return -1;
		}
		pos += ret;
		len -= ret;
	}

	return 0;
}

static int write_comm(unsigned int tmpfile_no, struct msg_cmt_st **cmt)
{
	FILE *fp;
	char tmpfile[TMP_FILE_MAX_LEN];

	sprintf(tmpfile, TMP_FILE_FMT_STR, tmpfile_no);
	fp = fopen(tmpfile, "w");
	if (fp == NULL) {
		return -1;
	}

	fputc((*cmt)->msg_level + '0', fp);
	fputc('\n', fp);
	fputc((*cmt)->host_map + '0', fp);
	fputc('\n', fp);
	fputs((*cmt)->data, fp);

	fclose(fp);

	return 0;
}